
/* GCSx
** LAYER.H
**
** Layer storage format and layer-related functions
** Doesn't include any editor-only functionality
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#ifndef __GCSx_LAYER_H_
#define __GCSx_LAYER_H_

// (should never be used as a LoadOnly item- always called from a scene;
//  doesn't follow spec exactly, ie LoadContent doesn't kill FileRead ptr, etc.)
class Layer /* : virtual public LoadOnly */ {
public:
    // Types of layers available
    enum LayerType {
        LAYER_EMPTY,
        LAYER_TILE,
        LAYER_IMAGE,
        LAYER_FONT,
    };
    
    // Bitmasks for layer data
    enum {
        // Layer data
        LAYER_TILE_INDEX   = 0x0000FFFF,
        LAYER_TILE_COLOR   = 0x0FFF0000,
        LAYER_TILE_COLOR_R = 0x000F0000,
        LAYER_TILE_COLOR_G = 0x00F00000,
        LAYER_TILE_COLOR_B = 0x0F000000,
        LAYER_TILE_COLOR_BITDEPTH = 4,
        LAYER_TILE_COLOR_SHIFT = 16,
        LAYER_TILE_FLIP    = 0x10000000,
        LAYER_TILE_MIRROR  = 0x20000000,
        LAYER_TILE_ROTATE  = 0x40000000,
        LAYER_TILE_ORIENTATION = 0x70000000,
        LAYER_TILE_COLLISION = 0x80000000,
        
        // Extended data
        LAYER_EXT_COLL     = 0x000007FF,
        LAYER_EXT_COLLTYPE = 0x0000F800,
        LAYER_EXT_ALPHA    = 0x000F0000,
        LAYER_EXT_ALPHA_BITDEPTH = 4,
        LAYER_EXT_ALPHA_SHIFT = 16,
        LAYER_EXT_ANIMON   = 0x00100000,
        LAYER_EXT_ANIMREV  = 0x00200000,
        LAYER_EXT_UNUSED   = 0xFFC00000,
        
        // Effects data
        LAYER_FX_UNDEFINED = 0xFFFFFFFF,
        
        // Default layer and effects when empty/clearing (no collision, for optimized)
        LAYER_TILE_DEFAULT  = LAYER_TILE_COLOR,
        LAYER_EXT_DEFAULT   = LAYER_EXT_ALPHA,
        LAYER_FX_DEFAULT    = 0,
        
        // Default mask used when flood filling/wand selecting
        LAYER_TILE_FILL_MASK= LAYER_TILE_INDEX | LAYER_TILE_COLOR | LAYER_TILE_FLIP | LAYER_TILE_MIRROR | LAYER_TILE_ROTATE,
    };

protected:
    std::string name;
    std::string nameL;
    class World* world;
    class Scene* scene;
    int cached; // If we haven't been asked to loadContent yet
    int lockCount;
    int lockCountPlay;

    // Numeric ID- computer-generated- unique to world- nonzero
    // Most functions refer to layers by their scene and z position,
    // but this is used by undo and a few other obscure things
    int id;

    // Type of layer (only LAYER_EMPTY and LAYER_TILE supported at this time)
    LayerType layerType;
    
    // Layer size in tiles for LAYER_TILE, in pixels for _FONT and _IMAGE
    int xSize;
    int ySize;
    
    // Spawns on this layer- ptrs owned by us; no NULL ptrs allowed
    // Vector, for quick traversal (initial spawn/display) and quick searching/sorting
    std::vector<class Spawn*> spawns; // part of "header"
      
    // LAYER_TILE layers

    // Tile set being used
    // These should remain static (other than being cached/uncached) during
    // normal gameplay; LayerEdit class knows how to handle them changing
    // and will be kept updated by appropriate methods; tileset cannot be
    // deleted if in use by any layer anywhere
    int tilesetId; // If 0, no tileset selected yet
    class TileSet* tileset; // Not owned by us
    
    // Layer data-
    // 16bits - tile index
    // 12bits - tile color (RGB 4bits each)
    //  3bits - orientation- flip, mirror, rotate90 (affects default collision maps too)
    //  1bit  - collisions- default enabled (default map, type 0)
    //          (this bit is ignored if collision data present)
    Uint32* tileData; // CACHEABLE
    
    // Extended data- (optional)
    // 11bits - collision map- 0 all off, 7FF all on, other user-defined
    //  5bits - collision type (0 to 31)
    //  4bits - translucency (alpha)
    //  2bits - animation (enabled, reverse)
    // 10bits - (unused currently)
    Uint32* extendedData; // CACHEABLE
    int usesExtended;
    
    // Effects data- (optional) (unused currently)
    Uint32* effectsData; // CACHEABLE
    int usesEffects;

    enum {
        // Default tile layer size in each direction
        LAYER_TILE_DEFAULT_SIZE = 64,
    };
    
    virtual int doLock(int play) throw_File;
    virtual int doUnlock(int play);
    void loadHeaderNonSpawns(class FileRead* file);
    
    // NON-EDITOR, GAMEPLAY DATA (not saved by editor)

    // Sprite lookup by name- this layer only
    SpriteIndex spritesById;

    // Sprites in display order, for this layer only
    SpriteOrder spritesByOrder;
    
    // Sub-functions for draw routine
    void drawTile(int viewX, int viewY);
    void drawSprites(int viewX, int viewY);
    
public:
    // Creates a default properties (empty) layer
    // Id must be unique; use ID of 0 if we're going to load anyways
    Layer(class World* myWorld, class Scene* myScene, int myId = 0);
    virtual ~Layer();
    
    // Accessors
    const std::string& getName() const { return name; }
    const std::string& getNameL() const { return nameL; }
    const class World* getWorld() const { return world; }
    class World* getWorld() { return world; }
    const class Scene* getScene() const { return scene; }
    class Scene* getScene() { return scene; }
    LayerType getType() const { return layerType; }
    int getXSize() const;
    int getYSize() const;
    int getId() const { return id; }
    int getBlockType() const { return WorldFileLoad::BLOCKTYPE_UNUSED; }

    // LAYER_TILE accessors
    const class TileSet* getTileSet() const { return tileset; }
    class TileSet* getTileSet() { return tileset; }
    int getUsesExt() const { return usesExtended; }
    int getUsesFx() const { return usesEffects; }
    
    // Load data from file- only Scene should call these
    // Layer assumes scene will call us with these when appropriate
    // loadHeader sets cached to 1, loadContent changes it back to 0
    virtual void loadHeader(class FileRead* file) throw_File;
    void loadContent(class FileRead* file) throw_File;
    void cacheLoad();
    
    // Recache data (just content) set cached back to 1
    // Layer assumes scene will call us with this only when we're not in use
    // and assumes scene won't call this if we're modified
    void recacheContent();

    // Marks tileset or any other resources we use as locked/unlocked
    // 'play' versions don't retain source tileset data- only textures
    int markLock() throw_File;
    int markLockPlay() throw_File;
    int markUnlock();
    int markUnlockPlay();
    int isContentCached() const;
    int isLocked() const;
    
    // GAMEPLAY

    // working with sprites
    // First places in all indices including world's- call on create/delete
    // Also activates/deactivates if we're locked
    void indexSprite(Sprite* addSprite);
    void deindexSprite(Sprite* remSprite);
    // Second modifies priority order only- use only when just changing priority
    void orderSprite(Sprite* addSprite);
    void deorderSprite(Sprite* remSprite);

    // do initial spawning- each spawn becomes an object/sprite
    void spawnLayer();
    
    // draws onscreen, over anything existing
    // draws sprites as well
    void draw(int viewX, int viewY);
};

#endif
